package model;

import java.util.Arrays;

import model.genetic.FitnessCounter;

public class SudokuValidator {
	
	public static final int size = 9;
	
	private boolean[][] validity;
	private boolean atLeastOneInvalid = false;
	private SudokuInterface sudoku;

	public SudokuValidator(SudokuInterface sudoku) {
		this.sudoku = sudoku;
		validity = new boolean[size][size];
		for (int i = 0; i < validity.length; ++i)
			Arrays.fill(validity[i], true);
	}
	
	public boolean validate() {
		for (int x = 0; x < size; ++x) {
			for (int y = 0; y < size; ++y) {
				if (validity[x][y]) {
					evaluateRow(y);
					evaluateColumn(x);
					evaluateSquare(x, y);
				}
			}
		}
		
		return !atLeastOneInvalid;
	}
	
	private void evaluateSquare(int x, int y) {
		int sqrtSize = (int) Math.sqrt(size);
		int xstart = (x / sqrtSize) * sqrtSize;
		int ystart = (y / sqrtSize) * sqrtSize;
		
		boolean isValid = true;
		
		FitnessCounter counter = new FitnessCounter(size);
		for(int i = xstart; i < (xstart + sqrtSize) && isValid; ++i) {
			for(int j = ystart;  j < (ystart + sqrtSize) && isValid; ++j) {
				int value = sudoku.getValueAt(i, j);
				if(value != -1) {
					isValid = counter.occurred(value);
				}
			}
		}
		
		if (!isValid) {
			atLeastOneInvalid = true;
			for(int i = xstart; i < (xstart + sqrtSize); ++i)
				for(int j = ystart;  j < (ystart + sqrtSize); ++j) 
					validity[i][j] = false;
		}
	}

	private void evaluateColumn(int x) {
		boolean isValid = true;
		
		FitnessCounter counter = new FitnessCounter(size);
		for (int y = 0; y < size && isValid; ++y) {
			int value = sudoku.getValueAt(x, y);
			if (value != -1)
				isValid = counter.occurred(value);
		}
		
		if (!isValid) {
			atLeastOneInvalid = true;
			for (int y = 0; y < size; ++y)
				validity[x][y] = false;
		}
	}

	private void evaluateRow(int y) {
		boolean isValid = true;
		
		FitnessCounter counter = new FitnessCounter(size);
		for (int x = 0; x < size && isValid; ++x) {
			int value = sudoku.getValueAt(x, y);
			if (value != -1)
				isValid = counter.occurred(value);
		}
		
		if (!isValid) {
			atLeastOneInvalid = true;
			for (int x = 0; x < size; ++x)
				validity[x][y] = false;
		}
	}

	public boolean isCellValid(int x, int y) {
		return validity[x][y];
	}

}
